package com.xy.biz.base.manager.impl;

import com.xy.biz.base.dao.DictDao;
import com.xy.biz.base.dao.DictGroupDao;
import com.xy.biz.base.dao.DictPropertyDao;
import com.xy.biz.base.domain.bo.DictBO;
import com.xy.biz.base.domain.bo.DictPropertyBO;
import com.xy.biz.base.domain.converter.DictConverter;
import com.xy.biz.base.domain.dto.DictPropertyDTO;
import com.xy.biz.base.domain.po.DictPO;
import com.xy.biz.base.domain.po.DictPropertyPO;
import com.xy.biz.base.domain.query.DictQuery;
import com.xy.biz.base.domain.req.GetDictByCodeRequest;
import com.xy.biz.base.domain.req.GetDictRequest;
import com.xy.biz.base.domain.req.ListDictItemRequest;
import com.xy.biz.base.domain.req.UpdateDictAllRequest;
import com.xy.biz.base.domain.resp.ListDictItemResponse;
import com.xy.biz.base.manager.DictManager;
import com.xy.lang.domain.StringKeyValue;
import com.xy.lang.domain.treeing.TreeItem;
import com.xy.lang.util.CollectionUtilsEx;
import com.xy.tool.context.UserContextHolder;
import com.xy.tool.util.BeanUtilsEx;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.lang.reflect.Array;
import java.util.*;
import java.util.stream.Collectors;

/**
 *
 *
 * @author zsp
 * @date 2020-5-23
 */
@Service
public class DictManagerImpl implements DictManager {

    @Autowired
    private DictGroupDao dictGroupDao;
    @Autowired
    private DictDao dictDao;
    @Autowired
    private DictPropertyDao dictPropertyDao;

    @Transactional
    @Override
    public DictBO saveDict(DictBO dictBO) {
        DictPO dictPO = DictConverter.toPO(dictBO);

        int row = dictDao.saveDict(dictPO);

        if (row > 0) {
            dictBO.setDictId(dictPO.getDictId());
            List<DictPropertyBO> propertyList = dictBO.getPropertyList();
            if (!CollectionUtils.isEmpty(propertyList)) {
                List<DictPropertyPO> dictPropertyPOList = BeanUtilsEx.copyPropertiesForNewList(propertyList, () -> new DictPropertyPO());
                dictPropertyPOList.forEach(e -> {
                    e.setDictId(dictPO.getDictId());
                });
                dictPropertyDao.saveAllDictProperty(dictPropertyPOList);
            }
        }
        return DictConverter.fromPO(dictPO);
    }

    /**
     * 更新
     *
     * @param dictBO
     */
    @Override
    public int updateDictName(DictBO dictBO) {
        return dictDao.updateDictName(DictConverter.toPO(dictBO));
    }

    @Transactional
    @Override
    public int updateDict(DictBO dictBO) {
        int affectedRows = dictDao.updateDict(DictConverter.toPO(dictBO));
        if (affectedRows > 0) {
            List<DictPropertyBO> addList = dictBO.getAddList();
            if (!CollectionUtils.isEmpty(addList)) {
                dictPropertyDao.saveAllDictProperty(BeanUtilsEx.copyPropertiesForNewList(addList, () -> new DictPropertyPO()));
            }
            List<DictPropertyBO> intersectionList = dictBO.getIntersectionList();
            if (!CollectionUtils.isEmpty(intersectionList)) {
                dictPropertyDao.restoreAllDictProperty(intersectionList.stream().map(DictPropertyBO::getDictPropertyId).collect(Collectors.toList()));
            }
            List<DictPropertyBO> subtractList = dictBO.getSubtractList();
            if (!CollectionUtils.isEmpty(subtractList)) {
                dictPropertyDao.deleteAllDictProperty(subtractList.stream().map(DictPropertyBO::getDictPropertyId).collect(Collectors.toList()));
            }
        }
        return affectedRows;
    }

    @Transactional
    @Override
    public int deleteDict(Long dictId) {
        int affectedRows = dictDao.deleteDict(dictId);
        if (affectedRows > 0) {
            dictPropertyDao.deleteDictPropertyByDictId(dictId);
        }
        return affectedRows;
    }

    @Override
    public boolean isDictExists(Long dictId) {
        return dictDao.isDictExists(dictId);
    }

    @Override
    public DictBO getDict(GetDictRequest request) {
        DictBO dictBO = DictConverter.fromPO(dictDao.getDict(request.getDictId()));
        if (dictBO != null) {
            if (request.getWithProperty() != null && request.getWithProperty().booleanValue()) {
                List<DictPropertyPO> dictPropertyPOList = dictPropertyDao.listDictPropertyByDictId(request.getDictId(),
                        request.getIgnorePropertyDeleteFlag() == null ? false : request.getIgnorePropertyDeleteFlag().booleanValue());
                if (!CollectionUtils.isEmpty(dictPropertyPOList)) {
                    dictBO.setPropertyList(BeanUtilsEx.copyPropertiesForNewList(dictPropertyPOList,
                            () -> new DictPropertyBO()));
                }
            }
        }
        return dictBO;
    }

    @Override
    public ListDictItemResponse getDictItem(GetDictByCodeRequest request) {
        DictQuery dictQuery = BeanUtilsEx.copyProperties(request, () -> DictQuery.one().build());
        dictQuery.setTenantId(UserContextHolder.getTenantId());
        ListDictItemResponse listDictItemResponse = BeanUtilsEx.copyProperties(
                dictDao.getDictByCode(dictQuery), () -> new ListDictItemResponse());
        if (listDictItemResponse != null) {
            if (request.getWithProperty() != null && request.getWithProperty().booleanValue()) {
                List<DictPropertyPO> dictPropertyPOList = dictPropertyDao.listDictPropertyByDictId(listDictItemResponse.getDictId(), false);
                if (!CollectionUtils.isEmpty(dictPropertyPOList)) {
                    listDictItemResponse.setPropertyList(BeanUtilsEx.copyPropertiesForNewList(dictPropertyPOList,
                            () -> new ListDictItemResponse.ListDictItemPropertyResponse()));
                }
            }
        }
        return listDictItemResponse;
    }

    @Override
    public List<DictBO> listDict(DictQuery query) {
        List<DictBO> dictBOList = DictConverter.fromPO(dictDao.listDict(query));
        if (query.getWithParent() != null && query.getWithParent().booleanValue() && !CollectionUtils.isEmpty(dictBOList)) {
            CollectionUtilsEx.foreachSetParent(dictBOList,
                    DictBO::getDictId,
                    DictBO::getParentDictId,
                    e -> BeanUtilsEx.copyPropertiesForNewList(
                            dictBOList.stream()
                                    .filter(ee -> ee.getParentDict() != null)
                                    .map(DictBO::getParentDict)
                                    .collect(Collectors.toSet()),
                            () -> new DictBO()),
                    (dictBO, parentDictBO) -> dictBO.setParentDict(parentDictBO));
        }
        return dictBOList;
    }

    @Override
    public int countDict(DictQuery query) {
        return dictDao.countDict(query);
    }

    @Override
    public List<DictPropertyDTO> listDictProperty(GetDictRequest request) {
        boolean ignoreDeleteFlag = request.getIgnorePropertyDeleteFlag() == null ? false : request.getIgnorePropertyDeleteFlag();
        List<DictPropertyPO> dictPropertyPOList = dictPropertyDao.listDictPropertyByDictId(request.getDictId(), ignoreDeleteFlag);
        return BeanUtilsEx.copyPropertiesForNewList(dictPropertyPOList, () -> new DictPropertyDTO());
    }

    @Override
    public List<DictPropertyDTO> listDictProperties(GetDictRequest request) {
        boolean ignoreDeleteFlag = request.getIgnorePropertyDeleteFlag() == null ? false : request.getIgnorePropertyDeleteFlag();
        List<DictPropertyPO> dictPropertyPOList = dictPropertyDao.listDictPropertyByDictIds(request.getDictIdCollection(), ignoreDeleteFlag);
        return BeanUtilsEx.copyPropertiesForNewList(dictPropertyPOList, () -> new DictPropertyDTO());
    }


    @Override
    public List<ListDictItemResponse> listDictItem(ListDictItemRequest request) {
        DictQuery dictQuery = BeanUtilsEx.copyProperties(request, () -> DictQuery.max().build());
        dictQuery.setTenantId(UserContextHolder.getTenantId());
        List<ListDictItemResponse> listDictItemResponseList = BeanUtilsEx.copyPropertiesForNewList(
                dictDao.listDict(dictQuery), () -> new ListDictItemResponse());
        if (!CollectionUtils.isEmpty(listDictItemResponseList)) {
            listDictItemResponseList.sort(Comparator.comparing(ListDictItemResponse::getSequence));
            if (request.getWithProperty() != null && request.getWithProperty().booleanValue()) {
                List<DictPropertyPO> dictPropertyPOList = dictPropertyDao.listDictPropertyByDictIds(
                        listDictItemResponseList.stream().map(ListDictItemResponse::getDictId).collect(Collectors.toList()), false);
                if (!CollectionUtils.isEmpty(dictPropertyPOList)) {
                    Map<Long, List<DictPropertyPO>> map = dictPropertyPOList.stream().collect(Collectors.groupingBy(DictPropertyPO::getDictId));
                    for (ListDictItemResponse item : listDictItemResponseList) {
                        List<DictPropertyPO> subDictPropertyPOList = map.get(item.getDictId());
                        if (!CollectionUtils.isEmpty(subDictPropertyPOList)) {
                            item.setPropertyList(BeanUtilsEx.copyPropertiesForNewList(subDictPropertyPOList,
                                    () -> new ListDictItemResponse.ListDictItemPropertyResponse()));
                        }
                    }
                }
            }
        }
        return listDictItemResponseList;
    }

    @Override
    public int getMaxPropertyKey(Long dictId) {
        return dictPropertyDao.getMaxPropertyKey(dictId);
    }

    @Override
    public List<StringKeyValue> listDictGroupItem(Integer type) {
        return dictGroupDao.listDictGroupItem(type);
    }

    @Override
    public List<Long> listParentDictId(Long dictId) {
        return dictDao.listParentDictId(dictId);
    }

    @Override
    public List<Long> listChildrenDictId(Long dictId) {
        return dictDao.listChildrenDictId(dictId);
    }

    @Override
    public List<TreeItem> listDictGroupItemAll(Integer type) {
        List<StringKeyValue> stringKeyValues = dictGroupDao.listDictGroupItem(type);
        Set<String> collect = stringKeyValues.stream().map(e -> e.getKey()).collect(Collectors.toSet());
        List<DictPO> dictPOS = dictDao.listDictItemByDictGroupList(collect);
        Map<String, List<DictPO>> collect1 = dictPOS.stream().collect(Collectors.groupingBy(e -> e.getDictGroupCode()));
        List<TreeItem> list = new ArrayList<>();
        for (StringKeyValue stringKeyValue : stringKeyValues) {
            TreeItem treeItem = new TreeItem();
            treeItem.setLabel(stringKeyValue.getKey());
            treeItem.setValue(stringKeyValue.getValue());
            List<DictPO> dictPOS1 = collect1.get(stringKeyValue.getKey());
            if (CollectionUtils.isEmpty(dictPOS1)) {
                break;
            }
            List<TreeItem> list1 = new ArrayList<>();
            for (DictPO dictPO : dictPOS1) {
                TreeItem treeItem1 = new TreeItem();
                treeItem1.setLabel(dictPO.getDictCode());
                treeItem1.setValue(dictPO.getDictValue());
                list1.add(treeItem1);
            }
            treeItem.setChildren(list1);
            list.add(treeItem);
        }
        return list;
    }

    @Override
    public List<TreeItem> listDictGroupItemByGroupCode(ListDictItemRequest request) {
        DictQuery query = DictConverter.toQuery(request);
        List<StringKeyValue> stringKeyValues = dictGroupDao.listDictGroup(query);
        Set<String> collect = stringKeyValues.stream().map(e -> e.getKey()).collect(Collectors.toSet());
        List<DictPO> dictPOS = dictDao.listDictItemByDictGroupList(collect);
        Map<String, List<DictPO>> collect1 = dictPOS.stream().collect(Collectors.groupingBy(e -> e.getDictGroupCode()));
        List<TreeItem> list = new ArrayList<>();
        for (StringKeyValue stringKeyValue : stringKeyValues) {
            TreeItem treeItem = new TreeItem();
            treeItem.setLabel(stringKeyValue.getKey());
            treeItem.setValue(stringKeyValue.getValue());
            List<DictPO> dictPOS1 = collect1.get(stringKeyValue.getKey());
            if (CollectionUtils.isEmpty(dictPOS1)) {
                break;
            }
            List<TreeItem> list1 = new ArrayList<>();
            for (DictPO dictPO : dictPOS1) {
                TreeItem treeItem1 = new TreeItem();
                treeItem1.setLabel(dictPO.getDictCode());
                treeItem1.setValue(dictPO.getDictValue());
                treeItem1.setTag(dictPO.getDictId() + "");
                list1.add(treeItem1);
            }
            treeItem.setChildren(list1);
            list.add(treeItem);
        }
        return list;
    }

    @Override
    public Integer updateAll(UpdateDictAllRequest request) {
        return dictGroupDao.updateAll(request);
    }

}
